package jonaPad;

import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.StringReader;
import Jona.*;

import java.util.Vector;

public class ArgModelChecker2 {
		private final String[] statementTypes = {"issue","assumption","undefined"};
		private final int[] statementTypesStat = {ArgObject.ISSUE,ArgObject.ASSUMPTION,ArgObject.UNDEFINED};
		private final int NONE = 0;
		private final int ASTOKEN=1;
		private final int STATEMENTTYPETOKEN=2;
		private final int VARORNONETOKEN=3;
		private final int IFORTXTTOKEN=4;
		private final int LEFTBRACKETTOKEN=5;
		private final int COMMATOKENORRIGHTBRACKETTOKEN=6;
		private final int DOUBLEPOINTOREQUALSTOKEN=7;
		private final int IFVARTOKEN=8;		//=antecedent
		private final int THENTOKEN=9;
		private final int CONSEQUENTVARTOKEN=10;
		private final int EQUALSTOKEN=11;
		
		private Vector statements = new Vector();
		private ArgObject activeStatement;
	
		public Theory checkModel(String tmp) throws ModelException
		{
			boolean doNotAdd = false;
			
			statements.removeAllElements();
			Theory rt = new Theory();

			StringReader sis = new StringReader(tmp);
			StreamTokenizer st = new StreamTokenizer(sis);
			st.eolIsSignificant(true);
			st.quoteChar(34);
			st.wordChars(33,33);
			
			int expectedNextTokenType;
			
			boolean done = false;
			expectedNextTokenType = VARORNONETOKEN;			
			while (! done) {
			    int c = StreamTokenizer.TT_EOF;
			    try {
	    		    c = st.nextToken();
	    		} catch (IOException e) { break; }
			    switch (c) {
			        case StreamTokenizer.TT_EOF:
			            //rt += "<EOF>" + "\n";
			            done = true;
			            break;
			        case StreamTokenizer.TT_EOL:
			        	if(expectedNextTokenType > ASTOKEN)
			        	{
			        		switch(expectedNextTokenType)
			        		{
			        			case THENTOKEN: throw new ModelException("then expected at line " + (st.lineno() -1));
			        			case CONSEQUENTVARTOKEN: throw new ModelException("consequent variabele expected at line " +(st.lineno() -1) );
			        			case IFVARTOKEN: throw new ModelException("antecedent variabele expected at line " +(st.lineno() -1) );
			        			case VARORNONETOKEN: 
			        				activeStatement=null;
					        		expectedNextTokenType=VARORNONETOKEN;	
			        			break;
			        			case STATEMENTTYPETOKEN: throw new ModelException("statement type expected at line " +(st.lineno() -1) );
			        		}
			        	}
			        	else
			        	{
			        		if(!doNotAdd)
			        		{
			        			statements.add(activeStatement);
			        		}
			        		doNotAdd=false;
			        		activeStatement=null;
			        		expectedNextTokenType=VARORNONETOKEN;
			        	}
			            break;
			        case StreamTokenizer.TT_WORD:		        	
			        	String word = st.sval.toLowerCase();
			        	switch(expectedNextTokenType)
			        	{
			        		case IFORTXTTOKEN:
			        			if(!word.equals("if")) throw new ModelException("if expected at line " + st.lineno() );
			        			if(word.equals("if"))
			        			{
			        				Conditional c1 = new Conditional(activeStatement.getArgumentType(),null);
			        				c1.setName(activeStatement.getName());
			        				activeStatement = c1; 	
			        			}
			        			expectedNextTokenType=LEFTBRACKETTOKEN;
			        		break;
			        		case EQUALSTOKEN:
			        			Variable.put(activeStatement.getName(),word);
			        			//System.out.println(activeStatement.getName()+" " +word);
			        			
			        			doNotAdd = true;
			        			//activeStatement = null;
			        			expectedNextTokenType=NONE;
			        		break;
			        		case ASTOKEN:
			        			if(!word.equals("as")) throw new ModelException("as expected at line " + st.lineno() );
			        			expectedNextTokenType=STATEMENTTYPETOKEN;
			        		break;
			        		case THENTOKEN:
			        			if(!word.equals("then"))throw new ModelException("then expected at line " + st.lineno());
			        			expectedNextTokenType=CONSEQUENTVARTOKEN;
			        		break;
			        		case CONSEQUENTVARTOKEN:
			        			foundConsequentVariabele(st.sval,st.lineno());
			        			expectedNextTokenType = ASTOKEN;
			        		break;
			        		case IFVARTOKEN:
			        			foundIfVariabele(st.sval,st.lineno());
			        			expectedNextTokenType=COMMATOKENORRIGHTBRACKETTOKEN;
			        		break;
			        		case VARORNONETOKEN:
			        			foundVariabele(st.sval,st.lineno());
			        			expectedNextTokenType=DOUBLEPOINTOREQUALSTOKEN;
			        		break;
			        		case STATEMENTTYPETOKEN:
			        			foundStatementType(word,st.lineno());
			        			expectedNextTokenType=NONE;
			        		break;
			        		default:
			        			throw new ModelException("Character(s) " + st.sval + " not expected at line " + st.lineno());
			        	}
			        	//rt += "W - '"+st.sval+"'" + "\n";
			            break;
			        case StreamTokenizer.TT_NUMBER:
			        	// rt += "N - '"+st.nval+"'" + "\n";
			            break;
			        default:
			        	boolean wasQuote = false;
			           	if ((c == 0x22) || (c == 0x27)) {
			            	  //System.out.println("" + st.sval);
			            	  //rt += ("Q - '"+st.sval+"'") + "\n";
			            	  if(expectedNextTokenType == IFORTXTTOKEN)
			            	  {   		  
			            		  foundTextStatement(st.sval,st.lineno());
			            		  expectedNextTokenType=ASTOKEN;
			            	  }
			            	  else if(expectedNextTokenType == EQUALSTOKEN)
			            	  {
			            		  Variable.put(activeStatement.getName(),st.sval);
			            		  expectedNextTokenType=NONE;
			            	  }
			            	  wasQuote = true;
			            }
			            if (! wasQuote)
			            {
			            	word = "" + (char)(st.ttype);
			            	switch(expectedNextTokenType)
			            	{
			            		case DOUBLEPOINTOREQUALSTOKEN:
			            			if(word.equals(":"))
			            				expectedNextTokenType=IFORTXTTOKEN;
			            			else if (word.equals("="))
			            				expectedNextTokenType=EQUALSTOKEN;
			            			else
			            				throw new ModelException(": Expected at line " + st.lineno());
			            		break;
			            		case LEFTBRACKETTOKEN:
			            			if(!word.equals("(")) throw new ModelException("( Expected at line " + st.lineno());
			            			expectedNextTokenType=IFVARTOKEN;
			            		break;
			            		case COMMATOKENORRIGHTBRACKETTOKEN:
			            			if(!word.equals(",") && !word.equals(")")) throw new ModelException(") or , Expected at line " + st.lineno());			            			
			            			if(word.equals(",")) expectedNextTokenType=IFVARTOKEN;
			            			else expectedNextTokenType = THENTOKEN;
			            		break;
			            		default:
			            			throw new ModelException("Character(s) " + word + " not expected at line " + st.lineno());
			            	
			            	}
			            }
			}			
		}
		createTheoryFromDumStatement(rt);
		return rt;
	}

    private void createTheoryFromDumStatement(Theory rt)
    {
    	for(int i =0; i < statements.size(); i++)
    	{
    		rt.addStatement((ArgObject)statements.get(i));
    	}
    }
		
	private void foundConsequentVariabele(String s, int line)throws ModelException
	{
		if(activeStatement != null)
		{
			boolean isNegated = false;
			
			if(s.startsWith("!")) 
			{	
				isNegated = true;
				//activeStatement = activeStatement.getNegation();
				s=s.substring(1);
			}
			int i =0;
			boolean found = false;
			while(i < statements.size() && !found)
			{
				if(((ArgObject)statements.get(i)).getName().equals(s))
				{
					if(!isNegated)((Conditional)activeStatement).setConsequent((((ArgObject)statements.get(i))));
					else ((Conditional)activeStatement).setConsequent( (((ArgObject)statements.get(i))).getNegation()  );
					found = true;
				}
				i++;
			}
			if(!found) throw new ModelException("Variabele(consequent) " + s + " unknown at line " + line);
		}		
	}
	private void foundIfVariabele(String s,int line)throws ModelException
	{
		//fill antecedent	
		if(activeStatement != null)
		{
			boolean isNegated = false;
			if(s.startsWith("!"))
			{	
				isNegated = true;
				s=s.substring(1);
			}
			int i =0;
			boolean found = false;
			while(i < statements.size() && !found)
			{
				if(((ArgObject)statements.get(i)).getName().equals(s))
				{
					if(!isNegated) ((Conditional)activeStatement).addAntecedent(((ArgObject)statements.get(i)));
					else ((Conditional)activeStatement).addAntecedent(((ArgObject)statements.get(i)).getNegation() );
					found = true;
				}
				i++;
			}
			if(!found) throw new ModelException("Variabele(antecedent) " + s + " unknown at line " + line);

		}
	}
	
	private void foundVariabele(String s,int line) throws ModelException
	{
		boolean isNegated = false;
		
		if(s.startsWith("!"))
		{
			isNegated = true;
			s=s.substring(1);
		}
		for(int i =0; i < statements.size(); i++)
		{
			if(s.equals(((ArgObject)statements.get(i)).getName())) throw new ModelException("Variabele " + s + " already exists. At line " + line);
		}
		activeStatement = new Statement();
		activeStatement.setArgumentType(statementTypesStat[2]);
		activeStatement.setName(s);
		if(isNegated) activeStatement=activeStatement.getNegation();
	}
		
    private void foundStatementType(String s, int line) throws ModelException
    {
    	if(activeStatement != null)
    	{
    		int i =0;
    		boolean found = false;
    		while(i < statementTypes.length && !found)
    		{
    			if(statementTypes[i].equals(s))
    			{
    				found = true;
    				activeStatement.setArgumentType(statementTypesStat[i]);
    			}
    			i++;
    		}
    		if(!found) throw new ModelException("Statement type unknown at line " + line);		
    	}
    }
    
    private void foundTextStatement(String s, int line) throws ModelException
    {
    	if(activeStatement != null)
    	{
    		activeStatement.setText(s);
    	}
    }

}

